//
//  BCDebugDirectoryBrowserPage.m
//  BCFileExplorer
//
//  Created by Ye Qing on 16/11/3.
//  Copyright © 2016年 Ye Qing. All rights reserved.
//

#import "BCDebugDirectoryBrowserPage.h"

#import <objc/runtime.h>

#import "BCDebugInteractiveLabel.h"
#import "BCDebugContextMenuCell.h"
#import "BCDebugTextEditPage.h"

#define ODK_FAVORITE_PATHS_PLIST_PATH    [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches/BCDebugKit/favorite_paths.plist"]

typedef NS_ENUM(NSUInteger, BCPathType) {
    BCPathTypeUnknown,  /**< the other paths */
    BCPathTypeHome,     /**< the path has home folder */
    BCPathTypeBundle,   /**< the path has bundle folder */
};

NSString *BCPathTypeUnknownKey = @"unknown";
NSString *BCPathTypeHomeKey = @"home";
NSString *BCPathTypeBundleKey = @"bundle";

static NSString *NSStringFromBCPathType(BCPathType pathType)
{
    switch (pathType) {
        case BCPathTypeUnknown:
        default:
            return BCPathTypeUnknownKey;
        case BCPathTypeHome:
            return BCPathTypeHomeKey;
        case BCPathTypeBundle:
            return BCPathTypeBundleKey;
    }
}

@interface BCPathItem ()
@property (nonatomic, copy, readwrite) NSString *path;
@property (nonatomic, copy) NSString *relativePath;
@property (nonatomic, assign) BCPathType pathType;
@end

@implementation BCPathItem
+ (instancetype)itemWithPath:(NSString *)path {
    BCPathItem *item = [[BCPathItem alloc] init];
    item.path = path;
    return item;
}

+ (instancetype)itemWithName:(NSString *)name path:(NSString *)path {
    BCPathItem *item = [self itemWithPath:path];
    item.name = name;
    return item;
}
@end

typedef NS_ENUM(NSInteger, BCActionSheetOperation) {
    BCActionSheetOperationCancel = 0,
    BCActionSheetOperationView = 1,
    BCActionSheetOperationExport,
};

static NSString* NSStringFromBCActionSheetOperation(BCActionSheetOperation operation) {
    switch (operation) {
        case BCActionSheetOperationView:
        default: {
            return NSLocalizedString(@"查看", nil);
        }
        case BCActionSheetOperationExport: {
            return NSLocalizedString(@"导出", nil);
        }
    }
}


//MARK: - UIAlertController Category
@interface UIAlertController (BCDebugDirectoryBrowserPage)
@property (nonatomic, strong) id userInfo;
@end

@implementation UIAlertController (BCDebugDirectoryBrowserPage)
@dynamic userInfo;
- (void)setUserInfo:(id)userInfo {
    objc_setAssociatedObject(self, @selector(userInfo), userInfo, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)userInfo {
    return objc_getAssociatedObject(self, @selector(userInfo));
}
@end

// File Attributes
static NSString *BCFileAttributeFileSize = @"BCFileAttributeFileSize";
static NSString *BCFileAttributeIsDirectory = @"BCFileAttributeIsDirectory";
static NSString *BCFileAttributeNumberOfFilesInDirectory = @"BCFileAttributeNumberOfFilesInDirectory";

#define ODK_SectionHeader_H 40.0f

@interface BCDebugDirectoryBrowserPage () <UITableViewDelegate, UITableViewDataSource, UIActionSheetDelegate, UISearchBarDelegate, BCDebugInteractiveLabelDelegate, BCDebugContextMenuCellDelegate>
@property (nonatomic, copy) NSString *pwdPath;  /**< current folder path */
@property (nonatomic, strong) NSArray *files;   /**< list name of files */
@property (nonatomic, strong) NSArray *filesFiltered; /**< list name of filtered files */
@property (nonatomic, strong) NSMutableDictionary *fileAttributes; /**< attributes of files */

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIDocumentInteractionController *documentController;

@property (nonatomic, strong) BCDebugInteractiveLabel *labelTitle;
@property (nonatomic, strong) NSArray *actionSheetOperations;

@property (nonatomic, strong) UISearchBar *searchBar;
@property (nonatomic, assign) BOOL isSearching;

@end

@implementation BCDebugDirectoryBrowserPage
#pragma mark -system
- (instancetype)initWithPath:(NSString *)path {
    self = [super init];
    if (self) {
        _pwdPath = path;
        _actionSheetOperations = @[ @(BCActionSheetOperationView), @(BCActionSheetOperationExport)];
    }
    return self;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.navigationItem setTitle:self.bctitle];
    self.view.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:self.tableView];
    if (self.pwdPath.length) {
        NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.pwdPath error:nil];
        self.files = [fileNames sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
        self.filesFiltered = [self.files copy];
        [self parseAttributesOfFiles];
    }
    [self.tableView setContentOffset:CGPointMake(0, CGRectGetHeight(self.searchBar.frame)) animated:NO];
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    if (self.isSearching) {
        [self.tableView setContentOffset:CGPointMake(0, 0) animated:NO];
    }
}
#ifdef DEBUG
- (void)dealloc {
    NSLog(@"BCDebugDirectoryBrowserPage dealloc");
}
#endif


#pragma mark - public

+ (NSArray<BCPathItem *> *)favoritePathItems
{
    NSMutableArray<BCPathItem *> *arrM = [NSMutableArray array];
    
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:ODK_FAVORITE_PATHS_PLIST_PATH];
    
    if ([dict isKindOfClass:[NSDictionary class]]) {
        
        for (NSString *path in dict[BCPathTypeHomeKey]) {
            
            BCPathItem *item = [BCPathItem itemWithPath:[NSHomeDirectory() stringByAppendingPathComponent:path]];
            item.pathType = BCPathTypeHome;
            item.relativePath = path;
            
            [arrM addObject:item];
        }
        
        for (NSString *path in dict[BCPathTypeBundleKey]) {
            BCPathItem *item = [BCPathItem itemWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:path]];
            item.pathType = BCPathTypeBundle;
            item.relativePath = path;
            
            [arrM addObject:item];
        }
        
        for (NSString *path in dict[BCPathTypeUnknownKey]) {
            BCPathItem *item = [BCPathItem itemWithPath:path];
            item.pathType = BCPathTypeUnknown;
            item.relativePath = path;
            
            [arrM addObject:item];
        }
    }
    
    return arrM;
}

+ (void)deleteFavoritePathItemWithItem:(BCPathItem *)item {
    BCPathType pathType = item.pathType;
    
    NSMutableDictionary *plistDictM = [NSMutableDictionary dictionary];
    
    NSData *data = [NSData dataWithContentsOfFile:ODK_FAVORITE_PATHS_PLIST_PATH];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    NSMutableDictionary *dictM = (NSMutableDictionary *)[NSPropertyListSerialization
                                                         propertyListFromData:data
                                                         mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                         format:0
                                                         errorDescription:nil];
#pragma GCC diagnostic pop
    
    [plistDictM addEntriesFromDictionary:dictM];
    
    NSMutableArray *arrM = [NSMutableArray arrayWithArray:dictM[NSStringFromBCPathType(pathType)]];
    
    NSString *pathToRemove = nil;
    for (NSString *path in arrM) {
        if ([path isEqualToString:item.relativePath]) {
            pathToRemove = path;
            break;
        }
    }
    
    if (pathToRemove) {
        [arrM removeObject:pathToRemove];
        plistDictM[NSStringFromBCPathType(pathType)] = arrM;
        
        BOOL success = [plistDictM writeToFile:ODK_FAVORITE_PATHS_PLIST_PATH atomically:YES];
        if (!success) {
            NSLog(@"delete path failed");
        }
    }
}


#pragma mark - Getters

- (BCDebugInteractiveLabel *)labelTitle {
    if (!_labelTitle) {
        BCDebugInteractiveLabel *label = [[BCDebugInteractiveLabel alloc] initWithFrame:CGRectZero];
        label.textAlignment = NSTextAlignmentCenter;
        label.font = [UIFont boldSystemFontOfSize:15.0f];
        label.lineBreakMode = NSLineBreakByTruncatingHead;
        label.textColor = [UIColor blueColor];
        label.contextMenuItemTypes = @[ @(BCDebugContextMenuItemCopy), @(BCDebugContextMenuItemView)];
        label.contextMenuItemTitles = @[ NSLocalizedString(@"复制", nil), NSLocalizedString(@"查看", nil) ];
        label.delegate = self;
        label.showContextMenuAlwaysCenetered = YES;
        
        _labelTitle = label;
    }
    
    return _labelTitle;
}

- (UITableView *)tableView {
    if (!_tableView) {
        CGSize screenSize = [[UIScreen mainScreen] bounds].size;
        CGFloat topInset = 0.0;
        UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, topInset, screenSize.width, screenSize.height - topInset) style:UITableViewStyleGrouped];
        tableView.delegate = self;
        tableView.dataSource = self;
        
        if(@available(iOS 11.0, *)) {
            tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
        UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, 44)];
        searchBar.delegate = self;
        searchBar.returnKeyType = UIReturnKeyDone;
        _searchBar = searchBar;
        
        tableView.tableHeaderView = searchBar;
        
        _tableView = tableView;
    }
    
    return _tableView;
}

#pragma mark

- (void)parseAttributesOfFiles {
    NSMutableArray *directories = [NSMutableArray array];
    
    NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
    for (NSString *fileName in self.files) {
        
        NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
        NSString *path = [self pathForFile:fileName];
        NSArray *subFileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
        
        BOOL isDirectory = NO;
        unsigned long long fileSize = [self sizefFileAtPath:path isDirectory:&isDirectory];
        
        attributes[BCFileAttributeIsDirectory] = @(isDirectory);
        if (!isDirectory) {
            // file
            attributes[BCFileAttributeFileSize] = @(fileSize);
        }
        else {
            // directory
            attributes[BCFileAttributeNumberOfFilesInDirectory] = @(subFileNames.count);
            [directories addObject:[fileName copy]];
        }
        
        if (attributes.count) {
            dictM[fileName] = attributes;
        }
    }
    
    self.fileAttributes = dictM;
    
    // calculate folder size
    if (directories.count) {
        __weak typeof(self) weak_self = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            for (NSString *fileName in directories) {
                if (weak_self == nil) {
                    // if the current view controller not exists, just abort loop
                    return;
                }
                
                NSString *path = [self pathForFile:fileName];
                NSError *error = nil;
                unsigned long long totalSize = [self sizeOfDirectoryAtPath:path error:&error];
                
                NSMutableDictionary *attributes = weak_self.fileAttributes[fileName];
                attributes[BCFileAttributeFileSize] = (error == nil ? @(totalSize) : error);
                
                // once a folder size is calculated, refresh table view to be more real time
                dispatch_async(dispatch_get_main_queue(), ^{
                    __strong BCDebugDirectoryBrowserPage *strong_self = weak_self;
                    [strong_self.tableView reloadData];
                });
            }
            
            // after all folders' size is calculated, refresh table view
            dispatch_async(dispatch_get_main_queue(), ^{
                __strong BCDebugDirectoryBrowserPage *strong_self = weak_self;
                [strong_self.tableView reloadData];
            });
        });
    }
}

#pragma mark - Utility

- (NSString *)pathForFile:(NSString *)file {
    return [self.pwdPath stringByAppendingPathComponent:file];
}

- (unsigned long long)sizefFileAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory {
    BOOL isDirectoryL = NO;
    BOOL isExisted = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectoryL];
    
    *isDirectory = isDirectoryL;
    if (isDirectoryL || !isExisted) {
        // If the path is a directory, or no file at the path exists
        return 0;
    }
    
    NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
    
    return [attributes[NSFileSize] unsignedLongLongValue];
}

- (unsigned long long)sizeOfDirectoryAtPath:(NSString *)path error:(NSError **)error {
    NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:path error:error];
    if (*error) {
        NSLog(@"error: %@", *error);
    }
    NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
    NSString *fileName;
    unsigned long long fileSize = 0;
    
    while (fileName = [filesEnumerator nextObject]) {
        NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[path stringByAppendingPathComponent:fileName] error:nil];
        fileSize += [fileDictionary fileSize];
    }
    
    return fileSize;
}

- (NSString *)prettySizeWithBytes:(unsigned long long)bytes {
    NSString *sizeString = [NSByteCountFormatter stringFromByteCount:bytes countStyle:NSByteCountFormatterCountStyleFile];
    return sizeString;
}

#pragma mark > Check Files

- (BOOL)fileIsDirectory:(NSString *)file {
    BOOL isDir = NO;
    NSString *path = [self pathForFile:file];
    [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
    return isDir;
}

- (BOOL)fileIsPlist:(NSString *)file {
    return [[file.lowercaseString pathExtension] isEqualToString:@"plist"];
}

- (BOOL)fileIsPicture:(NSString *)file {
    NSString *ext = [[file pathExtension] lowercaseString];
    
    return [ext isEqualToString:@"png"] || [ext isEqualToString:@"jpg"];
}

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.filesFiltered count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *sCellIdentifier = @"Cell";
    
    BCDebugContextMenuCell *cell = (BCDebugContextMenuCell *)[tableView dequeueReusableCellWithIdentifier:sCellIdentifier];
    if (cell == nil) {
        cell = [[BCDebugContextMenuCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:sCellIdentifier];
        cell.textLabel.font = [UIFont systemFontOfSize:16.0];
    }
    
    NSString *file = [self.filesFiltered objectAtIndex:indexPath.row];
    NSString *path = [self pathForFile:file];
    
    NSDictionary *attributes = self.fileAttributes[file];
    BOOL isDir = [attributes[BCFileAttributeIsDirectory] boolValue];
    
    cell.textLabel.text = file;
    cell.textLabel.textColor = isDir ? [UIColor blueColor] : [UIColor darkTextColor];
    
    NSString *sizeString = nil;
    if (attributes[BCFileAttributeFileSize] == nil) {
        sizeString = NSLocalizedString(@"正在计算大小...", nil);
    }
    else {
        if ([attributes[BCFileAttributeFileSize] isKindOfClass:[NSError class]]) {
            NSError *error = (NSError *)attributes[BCFileAttributeFileSize];
            sizeString = error.localizedDescription;
        }
        else {
            sizeString = [self prettySizeWithBytes:[attributes[BCFileAttributeFileSize] unsignedLongLongValue]];
        }
    }
    if (!isDir) {
        // file
        cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", sizeString];
    }
    else {
        // directory
        NSString *unit = [attributes[BCFileAttributeNumberOfFilesInDirectory] isEqualToNumber:@(1)] ? @"file" : @"files";
        cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@ (%@)", attributes[BCFileAttributeNumberOfFilesInDirectory], unit, sizeString];
    }
    cell.detailTextLabel.textColor = [UIColor grayColor];
    cell.accessoryType = isDir ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
    
    if (isDir) {
        cell.contextMenuItemTypes = @[ @(BCDebugContextMenuItemFavorite), @(BCDebugContextMenuItemView), @(BCDebugContextMenuItemCopy), @(BCDebugContextMenuItemShare)];
        cell.contextMenuItemTitles = @[ NSLocalizedString(@"收藏", nil), NSLocalizedString(@"查看", nil), NSLocalizedString(@"复制路径", nil), NSLocalizedString(@"导出", nil)];
    }
    else {
        cell.contextMenuItemTypes = @[ @(BCDebugContextMenuItemFavorite), @(BCDebugContextMenuItemView), @(BCDebugContextMenuItemCopy), @(BCDebugContextMenuItemProperty), @(BCDebugContextMenuItemShare)];
        cell.contextMenuItemTitles = @[ NSLocalizedString(@"收藏", nil),NSLocalizedString(@"查看", nil), NSLocalizedString(@"复制路径", nil), NSLocalizedString(@"属性", nil), NSLocalizedString(@"导出", nil)];
    }
    cell.allowCustomActionContextMenuItems = BCDebugContextMenuItemFavorite | BCDebugContextMenuItemView | BCDebugContextMenuItemCopy | BCDebugContextMenuItemShare | BCDebugContextMenuItemProperty;
    cell.delegate = self;
    
    if ([self fileIsPicture:file]) {
        UIImage *img = [UIImage imageWithContentsOfFile:path];
        cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
        cell.imageView.image = img;
    }
    else {
        cell.imageView.image = nil;
    }
    
    return cell;
}

#pragma mark - UITableViewDelegate

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    CGFloat paddingT = 15.0f;
    CGFloat paddingL = 15.0f;
    
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, ODK_SectionHeader_H)];
    
    if ([self.filesFiltered count]) {
        
        NSString *loadingTip = nil;
        unsigned long long totalSize = 0;
        
        for (NSString *file in self.filesFiltered) {
            NSDictionary *attributes = self.fileAttributes[file];
            
            if (attributes[BCFileAttributeFileSize] == nil) {
                loadingTip = NSLocalizedString(@"正在计算大小...", nil);
                break;
            }
            else {
                if ([attributes[BCFileAttributeFileSize] isKindOfClass:[NSNumber class]]) {
                    totalSize += [attributes[BCFileAttributeFileSize] unsignedLongLongValue];
                }
            }
        }
        
        NSString *unit = [self.filesFiltered count] == 1 ? @"item" : @"items";
        
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(paddingL, paddingT, screenSize.width - paddingL, 20)];
        label.text = [NSString stringWithFormat:@"%lu %@ (%@)", (unsigned long)[self.filesFiltered count], unit, loadingTip == nil ? [self prettySizeWithBytes:totalSize] : loadingTip];
        label.font = [UIFont systemFontOfSize:14.0f];
        label.textColor = [UIColor darkGrayColor];
        
        [view addSubview:label];
    }
    
    return view;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return ODK_SectionHeader_H;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    NSString *file = self.filesFiltered[indexPath.row];
    NSString *path = [self pathForFile:file];
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
    if ([self fileIsDirectory:file]) {
        //目录
        BCDebugDirectoryBrowserPage *vc = [[BCDebugDirectoryBrowserPage alloc] initWithPath:path];
        vc.bctitle = file;
        [self.navigationController pushViewController:vc animated:YES];
    }
    else {
        //文件
        [self.searchBar resignFirstResponder];
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"常用操作", nil) message:nil preferredStyle:UIAlertControllerStyleActionSheet];
        alertController.userInfo = path;
        for (NSUInteger i = 0; i < [self.actionSheetOperations count]; i++) {
            BCActionSheetOperation op = [self.actionSheetOperations[i] integerValue];
            __weak typeof(self) weak_self = self;
            UIAlertAction *action = [UIAlertAction actionWithTitle:NSStringFromBCActionSheetOperation(op) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                if (!weak_self) { return; }
                switch (op) {
                    case BCActionSheetOperationView: {
                        //查看文件
                        NSString *path = alertController.userInfo;
                        BCDebugTextEditPage *vc = [[BCDebugTextEditPage alloc] initWithFilePath:path];
                        [weak_self.navigationController pushViewController:vc animated:YES];
                        break;
                    }
                    case BCActionSheetOperationExport: {
                        //导出文件
                        NSString *path = alertController.userInfo;
                        NSURL *fileURL = [NSURL fileURLWithPath:path];
                        weak_self.documentController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
                        weak_self.documentController.UTI = @"public.data";
                        [weak_self.documentController presentOptionsMenuFromRect:CGRectZero inView:weak_self.view animated:YES];
                        break;
                    }
                    default:
                        break;
                }
            }];
            [alertController addAction:action];
        }
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"取消", nil) style:UIAlertActionStyleCancel handler:nil];
        [alertController addAction:cancelAction];
        [self presentViewController:alertController animated:YES completion:nil];
    }
}


#pragma mark - UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    [self.searchBar setShowsCancelButton:YES animated:YES];
    self.isSearching = YES;
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self.searchBar setShowsCancelButton:NO animated:YES];
    [self.searchBar resignFirstResponder];
    self.searchBar.text = @"";
    
    self.isSearching = NO;
    
    self.filesFiltered = [self.files copy];
    [self.tableView reloadData];
    
    CGFloat offsetY = CGRectGetHeight(self.searchBar.frame);
    [self.tableView setContentOffset:CGPointMake(0, offsetY) animated:YES];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    
    if (searchText.length) {
        NSMutableArray *arrM = [NSMutableArray array];
        
        for (NSString *fileName in self.files) {
            
            if ([fileName rangeOfString:searchText options:NSCaseInsensitiveSearch].location != NSNotFound) {
                [arrM addObject:fileName];
            }
        }
        
        self.filesFiltered = arrM;
    }
    else {
        self.filesFiltered = [self.files copy];
    }
    
    [self.tableView reloadData];
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    [self.searchBar resignFirstResponder];
}

#pragma mark - BCDebugInteractiveLabelDelegate

- (void)interactiveLabel:(BCDebugInteractiveLabel *)label contextMenuItemClicked:(BCDebugContextMenuItem)item withSender:(id)sender {
    if (item & BCDebugContextMenuItemView) {
        NSLog(@"view");
    }
    if (item & BCDebugContextMenuItemCopy) {
        NSLog(@"Copy");
    }
}

#pragma mark - BCDebugContextMenuCellDelegate

- (void)contextMenuCell:(BCDebugContextMenuCell *)cell contextMenuItemClicked:(BCDebugContextMenuItem)item withSender:(id)sender {
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];
    
    NSString *file = self.filesFiltered[indexPath.row];
    NSString *path = [self pathForFile:file];
    
    if (item & BCDebugContextMenuItemView) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:path delegate:nil cancelButtonTitle:NSLocalizedString(@"好的", nil) otherButtonTitles:nil];
        [alert show];
#endif
    }
    else if (item & BCDebugContextMenuItemCopy) {
        [UIPasteboard generalPasteboard].string = path;
    }
    else if (item & BCDebugContextMenuItemShare) {
        NSURL *fileURL = [NSURL fileURLWithPath:path];
        
        self.documentController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
        self.documentController.UTI = @"public.data";
        [self.documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
    }
    else if (item & BCDebugContextMenuItemProperty) {
        NSLog(@"BCDebugContextMenuItemProperty");
    }
    else if (item & BCDebugContextMenuItemFavorite) {
        NSLog(@"BCDebugContextMenuItemFavorite");
        [self doSavePathToFavorites:path];
    }
}

#pragma mark - Favorites

- (void)doSavePathToFavorites:(NSString *)path {
    BOOL isDirectory = NO;
    BOOL existed = [[NSFileManager defaultManager] fileExistsAtPath:ODK_FAVORITE_PATHS_PLIST_PATH isDirectory:&isDirectory];
    
    if (!existed || isDirectory) {
        if (isDirectory) {
            [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
        }
        
        NSString *directoryPath = [ODK_FAVORITE_PATHS_PLIST_PATH stringByDeletingLastPathComponent];
        
        if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:NULL]) {
            // create the directory
            [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil];
        }
        
        // create new file
        [[NSFileManager defaultManager] createFileAtPath:ODK_FAVORITE_PATHS_PLIST_PATH contents:nil attributes:nil];
    }
    
    NSString *relativePath = nil;
    BCPathType pathType = [self pathTypeForPath:path relativePath:&relativePath];
    
    NSMutableDictionary *plistDictM = [NSMutableDictionary dictionary];
    
    NSData *data = [NSData dataWithContentsOfFile:ODK_FAVORITE_PATHS_PLIST_PATH];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    NSMutableDictionary *dictM = (NSMutableDictionary *)[NSPropertyListSerialization
                                                         propertyListFromData:data
                                                         mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                                         format:0
                                                         errorDescription:nil];
#pragma GCC diagnostic pop
    
    [plistDictM addEntriesFromDictionary:dictM];
    
    NSMutableArray *arrM = [NSMutableArray arrayWithArray:dictM[NSStringFromBCPathType(pathType)]];
    
    if (pathType == BCPathTypeUnknown) {
        [arrM addObject:relativePath];
    }
    else if (pathType == BCPathTypeHome) {
        [arrM addObject:relativePath];
    }
    else if (pathType == BCPathTypeBundle) {
        [arrM addObject:relativePath];
    }
    
    plistDictM[NSStringFromBCPathType(pathType)] = arrM;
    
    BOOL success = [plistDictM writeToFile:ODK_FAVORITE_PATHS_PLIST_PATH atomically:YES];
    if (!success) {
        NSLog(@"write failed");
    }
}

- (BCPathType)pathTypeForPath:(NSString *)path relativePath:(NSString **)relativePath {
    static NSString *sHomeFolderName;
    static NSString *sBundleFolderName;
    
    NSString *relativePathL = [path copy];
    
    if (!sHomeFolderName) {
        sHomeFolderName = [NSHomeDirectory() lastPathComponent];
    }
    
    if (!sBundleFolderName) {
        sBundleFolderName = [[[NSBundle mainBundle] bundlePath] lastPathComponent];
    }
    
    if ([path rangeOfString:sHomeFolderName].location != NSNotFound) {
        NSRange range = [path rangeOfString:sHomeFolderName];
        relativePathL = [path substringFromIndex:range.location + range.length];
        *relativePath = [relativePathL stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
        
        return BCPathTypeHome;
    }
    else if ([path rangeOfString:sBundleFolderName].location != NSNotFound) {
        NSRange range = [path rangeOfString:sBundleFolderName];
        relativePathL = [path substringFromIndex:range.location + range.length];
        *relativePath = [relativePathL stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
        
        return BCPathTypeBundle;
    }
    else {
        *relativePath = relativePathL;
        return BCPathTypeUnknown;
    }
}

@end
